
from sqlalchemy import desc

from app.chess import db
from app.models import ChessMatch
from app.models import ChessGameProcess
from app.models import User
from app.models import GameDistrict


def session_rollback():
    db.session.rollback()


def begin_transction():
    db.session.begin_nested()


def delete_record(record):
    if not record:
        print("delete_record: record is None")
        return
    db.session.delete(record)


def session_commit():
    db.session.commit()


class BaseDAO(object):

    @classmethod
    def update_record(cls, record_id, info):
        model_cls = cls.model_cls
        row_obj = db.session.query(model_cls).filter(model_cls.id == record_id).first()
        if not row_obj:
            row_obj = model_cls()
            db.session.add(row_obj)
        #
        for k in cls.key_list:
            if k in info:
                setattr(row_obj, k, info.get(k))

        db.session.commit()

    @classmethod
    def get_record_by_username(cls, username):
        model_cls = cls.model_cls
        rv = db.session.query(model_cls).filter(model_cls.username == username).first()
        db.session.commit()
        return rv

    @classmethod
    def get_record(cls, record_id):
        model_cls = cls.model_cls
        row_obj = db.session.query(model_cls).filter(model_cls.id == record_id).first()
        return row_obj

    @classmethod
    def get_record_by_filter_key(cls, filter_key, get_all=False, limit_num=None):
        rv = db.session.query(cls.model_cls)
        # match_key = ('series', 'key')
        for k, v in filter_key.items():
            if type(v) in (list, tuple):
                rv = rv.filter(getattr(cls.model_cls, k).in_(v))
            else:
                rv = rv.filter(getattr(cls.model_cls, k) == v)
        #
        # res = None
        if get_all:
            if limit_num is None:
                res = rv.all()
            else:
                res = rv.all().limit(limit_num)
        else:
            #
            res = rv.first()
        db.session.commit()
        return res


class ChessGameProcessDAO(BaseDAO):
    key_list = ["match_id", "seq", "move", "dead_piece", "status", "update_time"]
    model_cls = ChessGameProcess

    @classmethod
    def get_match_record(cls, match_id):
        rv = db.session.query(ChessGameProcess).filter(ChessGameProcess.match_id == match_id).\
            order_by(ChessGameProcess.seq).all()
        return rv

    @classmethod
    def get_match_last_record(cls, match_id):
        rv = db.session.query(ChessGameProcess).filter(ChessGameProcess.match_id == match_id). \
            order_by(desc(ChessGameProcess.seq)).first()
        return rv

    @classmethod
    def delete_match_record(cls, match_id):
        db.session.query(ChessGameProcess).filter(ChessGameProcess.match_id == match_id).delete()
        db.session.commit()

    @classmethod
    def delete_match_record_some(cls, match_id, records):
        for item in records:
            db.session.delete(item)
        db.session.commit()


class UserDAO(BaseDAO):
    key_list = ('username', 'password', 'create_time')
    model_cls = User

    # @classmethod
    # def get_record_by_username(cls, username):
    #     rv = db.session.query(User).filter(User.username == username).first()
    #     return rv


class GameDistrictDAO(BaseDAO):
    key_list = ('uid', 'username', 'player', 'state', 'match_id', 'param', 'update_time')
    model_cls = GameDistrict

    @classmethod
    def get_unmatched_record(cls):
        rv = db.session.query(GameDistrict).filter(GameDistrict.state == 'Pending').limit(10).all()
        return rv


class ChessMatchDAO(BaseDAO):
    key_list = ('red_player', 'black_player', 'token', 'state', 'result', 'create_time')
    model_cls = ChessMatch

    @classmethod
    def get_red_machine_match(cls):
        rv = db.session.query(cls.model_cls).filter(cls.model_cls.red_player < 0).\
            filter(cls.model_cls.state != 'Finish').order_by(cls.model_cls.id).all()
        return rv

    @classmethod
    def get_black_machine_match(cls):
        rv = db.session.query(cls.model_cls).filter(cls.model_cls.black_player < 0). \
            filter(cls.model_cls.state != 'Finish').order_by(cls.model_cls.id).all()
        return rv


